package com.thz.friend.service.user.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.thz.common.core.constants.Constants;
import com.thz.common.core.constants.HttpConstants;
import com.thz.common.core.constants.RedisConstants;
import com.thz.common.core.enums.ResultCode;
import com.thz.common.core.enums.UserIdentity;
import com.thz.common.core.enums.UserStatus;
import com.thz.common.core.pojo.LoginUser;
import com.thz.common.core.pojo.vo.LoginUserVO;
import com.thz.common.core.result.Result;
import com.thz.common.core.utlis.ThreadLocalUtil;
import com.thz.exception.ApplicationException;
import com.thz.friend.manager.UserCacheManager;
import com.thz.friend.mapper.user.UserMapper;
import com.thz.friend.pojo.user.User;
import com.thz.friend.pojo.user.dto.UserEmailDTO;
import com.thz.friend.pojo.user.dto.UserUpdateDTO;
import com.thz.friend.pojo.user.vo.UserVO;
import com.thz.friend.rabbit.producer.MailProducer;
import com.thz.friend.service.user.IUserService;
import com.thz.redis.utlis.RedisUtil;
import com.thz.security.service.TokenService;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description
 * @Author thz
 * @Date 2025/3/26
 */
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private MailProducer mailProducer;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserCacheManager userCacheManager;

    // 发完一次验证码的等待时间
    @Value("${sms.code-expiration:5}")
    private Long emailCodeExpiration;

    // 一天最多提交的次数
    @Value("${sms.send-limit:3}")
    private Integer sendLimit;

    // 是否开启验证码
    @Value("${sms.is-send:false}")
    private boolean isSend;  //开关打开：true  开关关闭false

    @Value("${jwt.secret}")
    private String secret;

    // 用户初始头像
    @Value("${img.avatar:https://dongfangs.oss-cn-beijing.aliyuncs.com/forum/avatar01.jpeg}")
    private String avatar;

    @Value("${file.oss.downloadUrl}")
    private String downloadUrl;

    @Override
    public Boolean sendCode(UserEmailDTO userEmailDTO) {
        if(isValidEmail(userEmailDTO.getEmail())) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_ERROR_EMAIL));
        }
        String emailCodeKey = getEmailCodeKey(userEmailDTO.getEmail());
        Long expire = redisUtil.getExpire(emailCodeKey, TimeUnit.SECONDS);
        // 获取上次 redis 中的时间, 如果小于等待时间等待时间就 - 频繁
        if (expire != null && (emailCodeExpiration * 60 - expire) < 60 ){
            throw new ApplicationException(Result.failed(ResultCode.FAILED_FREQUENT));
        }
        // 获取单个邮箱的次数，如果超出就抛出异常
        String codeTimeKey = getCodeTimeKey(userEmailDTO.getEmail());
        Long sendTimes = redisUtil.getCacheObject(codeTimeKey, Long.class);
        if (sendTimes != null && sendTimes >= sendLimit) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_TIME_LIMIT));
        }
        String code = isSend ? RandomUtil.randomNumbers(6) : Constants.DEFAULT_CODE;
        redisUtil.setCacheObject(emailCodeKey, code, emailCodeExpiration , TimeUnit.MINUTES);
        if (isSend) {
            boolean sendMobileCode = mailProducer.sendMobileCode(userEmailDTO.getEmail(), code);
            if (!sendMobileCode) {
                throw new ApplicationException(Result.failed(ResultCode.FAILED_SEND_CODE));
            }
        }
        redisUtil.increment(codeTimeKey);
        if (sendTimes == null) {
            long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(),
                    LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0));
            redisUtil.expire(codeTimeKey, seconds, TimeUnit.SECONDS);
        }
        return true;
    }

    @Override
    public String codeLogin(String email, String code) {
        if(isValidEmail(email)) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_ERROR_EMAIL));
        }
        checkCode(email, code);
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email));
        if (user == null) {
            user = createUser(email);
            userMapper.insert(user);
        }
        // 生成登入 token
        return tokenService.createToken(user.getUserId(), secret, UserIdentity.ORDINARY.getValue(), user.getNickName(), user.getHeadImage());
    }

    private User createUser(String email){
        User user = new User();
        user.setEmail(email);
        user.setStatus(UserStatus.Normal.getValue());
        user.setCreateUser(Constants.SYSTEM_USER_ID);
        user.setNickName(UserIdentity.ORDINARY.getDes() + RandomStringUtils.randomAlphabetic(5));
        user.setHeadImage(avatar);
        return user;
    }


    @Override
    public Boolean logout(String token) {
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }
        return tokenService.deleteLoginUser(token, secret);
    }

    @Override
    public LoginUserVO info(String token) {
        // 1.截取token并且解析
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }
        // 2.解析token
        LoginUser loginUser = tokenService.getLoginUser(token, secret);
        if (loginUser == null) {
            throw new ApplicationException(Result.failed(ResultCode.USER_GET_MESSAGE_ERROR));
        }
        return LoginUserVO.builder()
                .nickName(loginUser.getNickName())
                .headImage(downloadUrl+loginUser.getHeadImage())
                .build();
    }

    @Override
    public UserVO detail() {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        if (userId == null) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        UserVO userVO = userCacheManager.getUserById(userId);
        if (userVO == null) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        userVO.setHeadImage(downloadUrl + userVO.getHeadImage());
        return userVO;
    }

    @Override
    public int edit(UserUpdateDTO userUpdateDTO) {
        // 获取当前用户的信息
        User user = checkUser();
        user.setNickName(userUpdateDTO.getNickName());
        user.setSex(userUpdateDTO.getSex());
        user.setSchoolName(userUpdateDTO.getSchoolName());
        user.setMajorName(userUpdateDTO.getMajorName());
        user.setPhone(userUpdateDTO.getPhone());
        user.setEmail(userUpdateDTO.getEmail());
        user.setWechat(userUpdateDTO.getWechat());
        user.setIntroduce(userUpdateDTO.getIntroduce());
        // 更新缓存
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);
        userCacheManager.refreshUser(userVO);
        // 更新登入时候存入的缓存
        tokenService.updateLoginUser(user.getNickName(), user.getHeadImage(), ThreadLocalUtil.get(Constants.USER_KEY, String.class));
        return userMapper.updateById(user);
    }

    @Override
    public int updateHeadImage(String headImage) {
        User user = checkUser();
        user.setHeadImage(headImage);
        //更新用户缓存
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);
        userCacheManager.refreshUser(userVO);
        tokenService.updateLoginUser(user.getNickName(), user.getHeadImage(), ThreadLocalUtil.get(Constants.USER_KEY, String.class));
        return userMapper.updateById(user);
    }

    private User checkUser() {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        if (userId == null) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        return user;
    }

    private void checkCode(String email, String code) {
        String emailCodeKey = getEmailCodeKey(email);
        String cacheCode = redisUtil.getCacheObject(emailCodeKey, String.class);
        if (StrUtil.isEmpty(cacheCode)) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_INVALID_CODE));
        }
        if (!cacheCode.equals(code)) {
            throw new ApplicationException(Result.failed(ResultCode.FAILED_ERROR_CODE));
        }
        // 验证码比对成功，就删除验证码
        redisUtil.deleteObject(emailCodeKey);
    }

    private String getEmailCodeKey(String email) {
        return redisUtil.buildKey(RedisConstants.C_USER_LOGIN_CODE_KEY , email);
    }

    private String getCodeTimeKey(String email) {
        return redisUtil.buildKey(RedisConstants.C_USER_LOGIN_CODE_TIME_KEY , email);
    }

    private boolean isValidEmail(String email) {
        String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
        Pattern pattern = Pattern.compile(emailRegex);
        Matcher matcher = pattern.matcher(email);
        return !matcher.matches();
    }


}
